package core

import (
	"fmt"
	"io"
	"net"
	"time"
)

type TcpServer struct {
	port          uint16
	onClientEvent ClientEvent
	obj           any
	lastError     error
	raw           bool //原始的数据，未加工，默认值为false
}

func NewTcpServer() *TcpServer {
	return &TcpServer{port: 0, onClientEvent: nil, raw: false}
}
func (s *TcpServer) GetLastError() error {
	return s.lastError
}
func (s *TcpServer) OnEvent(obj any, call ClientEvent) *TcpServer {
	s.onClientEvent = call
	s.obj = obj
	return s
}
func (s *TcpServer) RawStream(res bool) *TcpServer {
	s.raw = res
	return s
}
func (s *TcpServer) Run(port uint16) error {
	s.port = port

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port))
	if err != nil {
		s.lastError = err
		return err
	}

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				s.lastError = err
				if s.onClientEvent != nil {
					s.onClientEvent(s.obj, conn, Client_Error, nil)
				}
				continue
			}
			go s.handleConnection(conn)
		}
	}()
	return nil
}

func (s *TcpServer) handleConnection(conn net.Conn) {
	defer conn.Close()
	if s.onClientEvent != nil {
		s.onClientEvent(s.obj, conn, Client_Connect, nil)
	}

	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.SetNoDelay(true)
		tcpConn.SetReadBuffer(1024 * 32)
		tcpConn.SetWriteBuffer(1024 * 32)            //视频流媒体服务 256K,IM 32K(保持10万并发)
		tcpConn.SetKeepAlive(true)                   // 保持长连接活跃
		tcpConn.SetKeepAlivePeriod(10 * time.Minute) // 减少保活探测频率
	}

	for {
		if s.raw {
			buf := make([]byte, 1460)
			length, err := conn.Read(buf)
			if err != nil {
				s.lastError = err
				if err == io.EOF {
					if s.onClientEvent != nil {
						s.onClientEvent(s.obj, conn, Client_DisConnect, nil)
					}
				} else {
					if s.onClientEvent != nil {
						s.onClientEvent(s.obj, conn, Client_Error, nil)
					}
				}
				break
			}
			if s.onClientEvent != nil {
				s.onClientEvent(s.obj, conn, Client_Data, buf[0:length])
			}
		} else {
			pack, _, err := ReadPackage(conn)

			if err != nil {
				s.lastError = err
				if err == io.EOF {
					if s.onClientEvent != nil {
						s.onClientEvent(s.obj, conn, Client_DisConnect, nil)
					}
				} else {
					if s.onClientEvent != nil {
						s.onClientEvent(s.obj, conn, Client_Error, nil)
					}
				}
				break
			}
			if s.onClientEvent != nil {
				s.onClientEvent(s.obj, conn, Client_Data, pack)
			}
		}
	}
}
